import { StageEvent } from './../../stage-event/entities/stage-event.entity';
import { Tournament } from './../../tournament/entities/tournament.entity';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import * as ExcelJS from 'exceljs';
import { TournamentService } from 'src/modules/tournament/tournament.service';
import { PlayerSignupService } from './player-signup.service';
import { groupBy } from 'lodash';
import { EventTypeText, playerSignupTypeEnum } from 'src/common/constant/enums';
import { Event } from 'src/modules/event/entities/event.entity';
import { Stage } from 'src/modules/stage/entities/stage.entity';
import { uniqWith } from 'lodash';

type PlayerSignupType = {
  _order: number;
  pairName: string;
  playerInfo: [
    name: string,
    gender: string,
    age: number,
    phone: string,
    idCard: string,
    organization: string,
    isMainPlayer: any,
  ];
  stageEventInfo?: Array<number>;
  categoryInfo?: Array<number>;
};
type SheetHeaderType = Array<{ header: string; key: string | number }>;
type SheetObjectType = {
  [eventName: string]: {
    players: Array<PlayerSignupType>;
    headers: {
      stageEventInfos?: SheetHeaderType;
      categoryInfos?: SheetHeaderType;
    };
  };
};
type PlayerSignupExcelType = Array<SheetObjectType>;

type ExportPlayersToExcelParamType = {
  tournamentId: number;
  categoryId?: number;
  eventId?: number;
  stageIndex: number;
};

@Injectable()
export class PlayerSignupExportService {
  constructor(
    private tournamentService: TournamentService,
    // private eventService: EventService,
    private playerSignupService: PlayerSignupService,
  ) {}
  async exportPlayersToExcel(
    param: ExportPlayersToExcelParamType,
  ): Promise<ExcelJS.Buffer> {
    const tournamentData = await this.getPlayerSignupData(param.tournamentId);
    const genPlayerSignupExcelData = this.genPlayerSignupExcelData(
      tournamentData,
      param,
    );
    const workbook = this.genExcelFile(genPlayerSignupExcelData);

    // // 返回 Buffer
    return await workbook.xlsx.writeBuffer();
  }
  async getPlayerSignupData(tournamentId: number): Promise<Tournament> {
    const tournamentDetail =
      await this.tournamentService.findForPlayerSignupExport(tournamentId);
    if (!tournamentDetail) {
      throw new HttpException('Tournament not found', HttpStatus.NOT_FOUND);
    }
    return tournamentDetail;
  }
  getCategoryInfo(
    tournament: Tournament,
    param: ExportPlayersToExcelParamType,
  ) {
    const stageIndex = param.stageIndex || 1;
    const { categoryId, eventId } = param;

    const matchCategoryInfo = [];
    tournament.categories.forEach((category) => {
      if (categoryId && categoryId !== category.id) {
        return;
      }
      category.events.forEach((event) => {
        if (eventId && eventId !== event.id) {
          return;
        }
        const _categoryInfo = {
          category,
          event,
        };
        event.stages.forEach((stage) => {
          const { stageOrderInEvent } = stage;
          if (stageOrderInEvent === stageIndex) {
            // 筛选出符合条件的（stageIndex） stage
            // matchCategoryInfo.push({
            //   category,
            //   event,
            //   stage,
            // });
            (_categoryInfo as any).stage = stage;
          }
        });
        matchCategoryInfo.push(_categoryInfo);
      });
    });
    if (matchCategoryInfo.length === 0) {
      throw new HttpException('Stage not found', HttpStatus.NOT_FOUND);
    }
    return matchCategoryInfo;
  }
  getStageEventHeader(stageEvents: Array<StageEvent>): SheetHeaderType {
    const res = [];
    stageEvents.forEach((stageEvent) => {
      res.push({
        header: `${EventTypeText[stageEvent.type]}-${stageEvent.eventOrder}`,
        key: stageEvent.id,
      });
    });
    return res;
  }
  genPlayerSignupExcelData(
    tournament: Tournament,
    param: ExportPlayersToExcelParamType,
  ): PlayerSignupExcelType {
    const res: PlayerSignupExcelType = [];
    const matchCategoryInfo = this.getCategoryInfo(tournament, param);
    // 按照 event 分组, 因为excel 是按照event 来分sheet的
    const matchCategoryGroupByEvent = groupBy(matchCategoryInfo, 'event.type');
    for (const eventType in matchCategoryGroupByEvent) {
      const eventName = EventTypeText[eventType];
      const sheetObject: SheetObjectType = {
        [eventName]: { players: [], headers: {} },
      };
      matchCategoryGroupByEvent[eventType].forEach((categoryInfo) => {
        const { category, event, stage } = categoryInfo;
        const { playerSignups } = event as Event;
        sheetObject[eventName].headers.categoryInfos =
          sheetObject[eventName].headers.categoryInfos || [];
        if (
          !sheetObject[eventName].headers.categoryInfos.find(
            (item) => item.key === category.id,
          )
        ) {
          // 只添加不存在的category
          sheetObject[eventName].headers.categoryInfos.push({
            header: category.name,
            key: category.id,
          });
        }

        if (stage && stage.stageOrderInEvent) {
          const { stageEvents } = stage as Stage;
          if (stageEvents.length) {
            sheetObject[eventName].headers.stageEventInfos =
              sheetObject[eventName].headers.stageEventInfos || [];
            sheetObject[eventName].headers.stageEventInfos.push(
              ...this.getStageEventHeader(stageEvents),
            );
          }
        }

        if (playerSignups.length) {
          playerSignups.forEach((playerSignup) => {
            const {
              _order,
              pairName,
              name,
              gender,
              age,
              idCard,
              phone,
              organization,
              isMainPlayer,
              stageEventId,
              type,
            } = playerSignup;
            if (type === playerSignupTypeEnum.team) {
              // 团队虚拟节点不展示
              return;
            }
            sheetObject[eventName].players.push({
              _order,
              pairName,
              playerInfo: [
                name,
                gender,
                age,
                idCard,
                phone,
                organization,
                isMainPlayer || '',
              ],
              stageEventInfo: [stageEventId],
              categoryInfo: [category.id],
            });
          });
        }
        // 去重
        sheetObject[eventName].headers.stageEventInfos = uniqWith(
          sheetObject[eventName].headers.stageEventInfos,
          (a, b) => a.header === b.header,
        );
        sheetObject[eventName].headers.categoryInfos = uniqWith(
          sheetObject[eventName].headers.categoryInfos,
          (a, b) => a.header === b.header,
        );
      });
      res.push(sheetObject);
    }
    return res;
  }
  genExcelFile(param: PlayerSignupExcelType) {
    const workbook = new ExcelJS.Workbook();
    for (const sheetObject of param) {
      for (const eventName in sheetObject) {
        const { players, headers } = sheetObject[eventName];
        const worksheet = workbook.addWorksheet(eventName);
        const { stageEventInfos, categoryInfos } = headers;
        const header1 = [
          { header: '', key: '' },
          { header: '', key: '' },
          { header: '选手', key: 'playerInfo' },
          ...new Array(6).fill({ header: '', key: 'playerInfoMerge' }),
        ];
        if (stageEventInfos && stageEventInfos.length) {
          header1.push(
            { header: '项目', key: 'stageEventInfo' },
            ...new Array(stageEventInfos.length - 1).fill({
              header: '',
              key: 'stageInfoMerge',
            }),
          );
        }
        if (categoryInfos && categoryInfos.length) {
          header1.push(
            { header: '组别', key: 'categoryInfo' },
            ...new Array(categoryInfos.length - 1).fill({
              header: '',
              key: 'categoryInfoMerge',
            }),
          );
        }
        const header2Single = [
          { header: '坑位', key: '_order', width: 10 },
          { header: '双打队名', key: 'pairName', width: 10 },
        ];
        const header2PlayerInfo = [
          { header: '姓名', key: 'name', width: 10 },
          { header: '性别', key: 'gender', width: 10 },
          { header: '年龄', key: 'age', width: 10 },
          { header: '身份证号', key: 'idCard', width: 30 },
          { header: '电话', key: 'phone', width: 30 },
          { header: '单位', key: 'organization', width: 30 },
          { header: '是否上场', key: 'isMainPlayer', width: 10 },
        ];
        const header2StageInfo = [];
        if (stageEventInfos && stageEventInfos.length) {
          stageEventInfos.forEach((stageEventInfo) => {
            header2StageInfo.push({
              header: `${stageEventInfo.header}`,
              key: stageEventInfo.key,
            });
          });
        }
        const header2CategoryInfo = [];
        if (categoryInfos && categoryInfos.length) {
          categoryInfos.forEach((categoryInfo) => {
            header2CategoryInfo.push({
              header: `${categoryInfo.header}`,
              key: categoryInfo.key,
            });
          });
        }
        // add first row header
        worksheet.addRow(header1.map((header) => header.header));
        // 合并单元格
        worksheet.mergeCells(
          1,
          header2Single.length + 1,
          1,
          header2Single.length + header2PlayerInfo.length,
        );
        if (header2StageInfo.length) {
          worksheet.mergeCells(
            1,
            header2Single.length + header2PlayerInfo.length + 1,
            1,
            header2Single.length +
              header2PlayerInfo.length +
              header2StageInfo.length,
          );
        }
        if (header2CategoryInfo.length) {
          worksheet.mergeCells(
            1,
            header2Single.length +
              header2PlayerInfo.length +
              header2StageInfo.length +
              1,
            1,
            header2Single.length +
              header2PlayerInfo.length +
              header2StageInfo.length +
              header2CategoryInfo.length,
          );
        }

        // add second row header
        worksheet.addRow([
          ...header2Single.map((header) => header.header),
          ...header2PlayerInfo.map((header) => header.header),
          ...header2StageInfo.map((header) => header.header),
          ...header2CategoryInfo.map((header) => header.header),
        ]);

        const totalColumns =
          header2Single.length +
          header2PlayerInfo.length +
          header2StageInfo.length +
          header2CategoryInfo.length;

        const columns = [...header2Single, ...header2PlayerInfo];
        for (let i = 1; i <= totalColumns; i++) {
          // 可以根据实际需求调整列宽
          worksheet.getColumn(i).width = columns[i - 1]?.width || 10;
        }

        players.forEach((player) => {
          const row = [];
          const { _order, pairName, playerInfo, stageEventInfo, categoryInfo } =
            player;
          row.push(_order, pairName, ...playerInfo);
          if (stageEventInfo && stageEventInfo.length) {
            header2StageInfo.forEach((headerInfo) => {
              if (stageEventInfo.includes(headerInfo.key)) {
                row.push('√');
              } else {
                row.push('');
              }
            });
          }
          if (categoryInfo && categoryInfo.length) {
            header2CategoryInfo.forEach((headerInfo) => {
              if (categoryInfo.includes(headerInfo.key)) {
                row.push('√');
              } else {
                row.push('');
              }
            });
          }
          worksheet.addRow(row);
        });
      }
    }
    return workbook;
  }
}
